package com.zl.gmadmin.configuration.secutity;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.zl.gmadmin.common.Status;
import com.zl.gmadmin.exception.SecurityException;
import com.zl.gmadmin.service.SysMenuService;
import com.zl.gmadmin.service.SysRoleService;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 认证服务,动态路由认证,验证请求是否存在以及权限是否匹配
 * @author zhangliang
 * @version 1.0
 * @date 2021/1/25 15:36
 */
@Component
public class RBACAuthorityService {

    private final SysRoleService roleService;


    private final SysMenuService menuService;
    

    private final RequestMappingHandlerMapping mapping;

    public RBACAuthorityService(SysRoleService roleService, SysMenuService menuService, RequestMappingHandlerMapping mapping) {
        this.roleService = roleService;
        this.menuService = menuService;
        this.mapping = mapping;
    }

    /**
     * 发送请求验证是否有权限
     * @param request
     * @param authentication
     * @return
     */
    public boolean hasPermission(HttpServletRequest request, Authentication authentication){
        //通过RequestMappingHandlerMapping校验请求是否存在
//        LogUtil.debug(this.getClass().getName()+":{}"+",地址:{}",request.getMethod(),request.getRequestURI());
//        LogUtil.debug("检查请求是否存在:{}", checkRequest(request));
//
//        Object userInfo=authentication.getPrincipal();
//        boolean hasPermission=false;

//        if (userInfo instanceof UserDetails){
//            UserPrincipal principal= (UserPrincipal) userInfo;
//            Long userId=principal.getId();
////            log.debug("用户id:{}",userId);
//
//            //根据用户id查询角色，再根据角色查询权限菜单
//            List<SysRole> roles=roleService.selectByUserId(userId);
//            Set<Long> roleIds=roles.stream().map(SysRole::getRoleId).collect(Collectors.toSet());
//
//            List<SysMenu> menus=menuService.selectByRoleIdList(roleIds);
//
//            //获取资源，前后端分离，所以过滤页面权限，只保留按钮权限,过来的是满足条件的
//            List<SysMenu> btnPerms=menus.stream()
//                     //过滤类型是按钮
//                    .filter(sysMenu-> Objects.equals(sysMenu.getType(), Consts.PAGE))
//                    //过滤组件为空
//                    .filter(sysMenu -> StrUtil.isNotEmpty(sysMenu.getComponent()))
//                    //过滤请求方法类型为空
//                    .filter(sysMenu -> StrUtil.isNotBlank(sysMenu.getMethod()) )
//                    .collect(Collectors.toList());
//
//            LogUtil.debug("按钮权限:{}",btnPerms.toString());
//            for (SysMenu s :btnPerms
//                    ) {
//                LogUtil.debug(this.getClass().getName()+":{}","当前用户的组件权限,"+s.getComponent());
//                AntPathRequestMatcher matcher=new AntPathRequestMatcher(s.getComponent(),s.getMethod());
//                //匹配请求是否有权限
//                if (matcher.matches(request)){
//                    LogUtil.debug(this.getClass().getName()+":{}","当前用户匹配的的权限,"+s.getComponent());
//                    hasPermission=true;
//                    break;
//                }
//            }
//            return hasPermission;
//
//        }

        return true;
    }

    /**
     * 校验请求是否存在
     *
     * @param request 请求
     */
    private boolean checkRequest(HttpServletRequest request) {
    String currentMethod=request.getMethod();
        Multimap<String,String> urlMapping=allUrlMapping();

        for (String  uri : urlMapping.keySet()){
            // 通过 AntPathRequestMatcher 匹配 url
            // 可以通过 2 种方式创建 AntPathRequestMatcher
            // 1：new AntPathRequestMatcher(uri,method) 这种方式可以直接判断方法是否匹配，因为这里我们把 方法不匹配 自定义抛出，所以，我们使用第2种方式创建
            // 2：new AntPathRequestMatcher(uri) 这种方式不校验请求方法，只校验请求路径
            AntPathRequestMatcher antPathMatcher = new AntPathRequestMatcher(uri);
            if (antPathMatcher.matches(request)) {
                if (!urlMapping.get(uri).contains(currentMethod)) {
                    throw new SecurityException(Status.HTTP_BAD_METHOD);
                } else {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 获取 所有URL Mapping，返回格式为{"/test":["GET","POST"],"/sys":["GET","DELETE"]}
     *
     * @return {@link ArrayListMultimap} 格式的 URL Mapping
     */
    private Multimap<String, String> allUrlMapping() {
        Multimap<String,String> urlMapping=ArrayListMultimap.create();

        // 获取url与类和方法的对应信息
        Map<RequestMappingInfo, HandlerMethod> handlerMethodMap=mapping.getHandlerMethods();

        handlerMethodMap.forEach((k,v)->{
            // 获取当前 key 下的获取所有URL
            Set<String> url=k.getPatternsCondition().getPatterns();
            RequestMethodsRequestCondition method=k.getMethodsCondition();


            url.forEach(s -> urlMapping.putAll(s,method.getMethods().stream().map(Enum::toString).collect(Collectors.toList())));
        });

        return urlMapping;
    }
}
